﻿using System;
using System.Web;
using System.Web.Caching;


namespace TSharp.Core.Caching
{
    #region Cache

    /// <summary>
    /// Cache通用操作类
    /// </summary>
    /// <author>
    /// tangjingbo
    /// </author>
    /// <remarks>
    /// tangjingbo at 2009-10-19 16:13
    /// </remarks>
    public static class CacheUtil
    {
        /// <summary>
        /// Gets the dic.
        /// </summary>
        private static Cache dic
        {
            get { return HttpRuntime.Cache; }
        }

        /// <summary>
        /// Adds the or update.
        /// </summary>
        /// <typeparam name="TValue">The type of the value.</typeparam>
        /// <param name="key">The key.</param>
        /// <param name="addValueFactory">The add value factory.</param>
        /// <param name="updateValueFactory">The update value factory.</param>
        /// <returns></returns>
        public static TValue AddOrUpdate<TValue>(string key, Func<string, TValue> addValueFactory,
                                                 Func<string, TValue, TValue> updateValueFactory)
        {
            object obj = dic.Get(key);
            if (obj == null)
                return SetValue(key, addValueFactory(key), true);
            else
            {
                var oldValue = (TValue)obj;
                TValue newValue = updateValueFactory(key, oldValue);
                return SetValue(key, newValue, !Equals(oldValue, newValue));
            }
        }

        /// <summary>
        /// Adds the or update.
        /// </summary>
        /// <typeparam name="TValue">The type of the value.</typeparam>
        /// <param name="key">The key.</param>
        /// <param name="addValueFactory">The add value factory.</param>
        /// <param name="updateValueFactory">The update value factory.</param>
        /// <param name="absoluteexpiration">The absoluteexpiration.</param>
        /// <param name="dependency">The dependency.</param>
        /// <param name="updatecallback">The updatecallback.</param>
        /// <returns></returns>
        public static TValue AddOrUpdate<TValue>(string key, Func<string, TValue> addValueFactory,
                                                 Func<string, TValue, TValue> updateValueFactory,
                                                 DateTime absoluteexpiration, CacheDependency dependency,
                                                 CacheItemUpdateCallback updatecallback)
        {
            return AddOrUpdate(key, addValueFactory, updateValueFactory, dependency, absoluteexpiration,
                               Cache.NoSlidingExpiration, updatecallback);
        }

        /// <summary>
        /// Adds the or update.
        /// </summary>
        /// <typeparam name="TValue">The type of the value.</typeparam>
        /// <param name="key">The key.</param>
        /// <param name="addValueFactory">The add value factory.</param>
        /// <param name="updateValueFactory">The update value factory.</param>
        /// <param name="slidingexpiration">The slidingexpiration.</param>
        /// <param name="dependency">The dependency.</param>
        /// <param name="updatecallback">The updatecallback.</param>
        /// <returns></returns>
        public static TValue AddOrUpdate<TValue>(string key, Func<string, TValue> addValueFactory,
                                                 Func<string, TValue, TValue> updateValueFactory,
                                                 TimeSpan slidingexpiration, CacheDependency dependency,
                                                 CacheItemUpdateCallback updatecallback)
        {
            return AddOrUpdate(key, addValueFactory, updateValueFactory, dependency, Cache.NoAbsoluteExpiration,
                               slidingexpiration, updatecallback);
        }

        /// <summary>
        /// Adds the or update.
        /// </summary>
        /// <typeparam name="TValue">The type of the value.</typeparam>
        /// <param name="key">The key.</param>
        /// <param name="addValueFactory">The add value factory.</param>
        /// <param name="updateValueFactory">The update value factory.</param>
        /// <param name="dependency">The dependency.</param>
        /// <param name="absoluteexpiration">The absoluteexpiration.</param>
        /// <param name="slidingexpiration">The slidingexpiration.</param>
        /// <param name="updatecallback">The updatecallback.</param>
        /// <returns></returns>
        private static TValue AddOrUpdate<TValue>(string key, Func<string, TValue> addValueFactory,
                                                  Func<string, TValue, TValue> updateValueFactory,
                                                  CacheDependency dependency, DateTime absoluteexpiration,
                                                  TimeSpan slidingexpiration, CacheItemUpdateCallback updatecallback)
        {
            object obj = dic.Get(key);
            if (obj == null)
                return SetValue(key, addValueFactory(key), dependency, absoluteexpiration, slidingexpiration, updatecallback, true);
            else
            {
                var oldValue = (TValue)obj;
                var newValue = updateValueFactory(key, oldValue);
                SetValue(key, newValue, dependency, absoluteexpiration, slidingexpiration, updatecallback, !Equals(oldValue, newValue));
                return newValue;
            }
        }

        /// <summary>
        /// Gets the specified key.
        /// </summary>
        /// <typeparam name="TValue">The type of the value.</typeparam>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        public static TValue Get<TValue>(string key)
        {
            return (TValue)dic.Get(key);
        }

        /// <summary>
        /// Gets the specified key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        public static object Get(string key)
        {
            return dic.Get(key);
        }
        /// <summary>
        /// Removes the specified key.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        public static object Remove(string key)
        {
            object value = dic.Get(key);
            dic.Remove(key);
            return value;
        }

        /// <summary>
        /// Gets the or add.
        /// </summary>
        /// <typeparam name="TValue">The type of the value.</typeparam>
        /// <param name="key">The key.</param>
        /// <param name="valueFactory">The value factory.</param>
        /// <returns></returns>
        public static TValue GetOrAdd<TValue>(string key, Func<string, TValue> valueFactory)
        {
            object obj = dic.Get(key);
            if (obj != null)
                return (TValue)obj;
            return SetValue(key, valueFactory(key), true);
        }

        /// <summary>
        /// Gets the or add.
        /// </summary>
        /// <typeparam name="TValue">The type of the value.</typeparam>
        /// <param name="key">The key.</param>
        /// <param name="valueFactory">The value factory.</param>
        /// <param name="absoluteexpiration">The absoluteexpiration.</param>
        /// <param name="dependency">The dependency.</param>
        /// <param name="updatecallback">The updatecallback.</param>
        /// <returns></returns>
        public static TValue GetOrAdd<TValue>(string key, Func<string, TValue> valueFactory, DateTime absoluteexpiration,
                                              Func<string, TValue, CacheDependency> dependency,
                                              CacheItemUpdateCallback updatecallback)
        {
            object obj = dic.Get(key);
            if (obj != null)
                return (TValue)obj;
            TValue value = valueFactory(key);
            return SetValue(key, value, dependency(key, value), absoluteexpiration, Cache.NoSlidingExpiration, updatecallback, true);
        }

        /// <summary>
        /// Gets the or add.
        /// </summary>
        /// <typeparam name="TValue">The type of the value.</typeparam>
        /// <param name="key">The key.</param>
        /// <param name="valueFactory">The value factory.</param>
        /// <param name="slidingexpiration">The slidingexpiration.</param>
        /// <param name="dependency">The dependency.</param>
        /// <param name="updatecallback">The updatecallback.</param>
        /// <returns></returns>
        public static TValue GetOrAdd<TValue>(string key, Func<string, TValue> valueFactory, TimeSpan slidingexpiration,
                                              Func<string, TValue, CacheDependency> dependency,
                                              CacheItemUpdateCallback updatecallback)
        {
            object obj = dic.Get(key);
            if (obj != null)
                return (TValue)obj;
            TValue value = valueFactory(key);
            return SetValue(key, value, dependency(key, value), Cache.NoAbsoluteExpiration, slidingexpiration, updatecallback, true);
        }

        /// <summary>
        /// Inserts the specified key.
        /// </summary>
        /// <typeparam name="TValue">The type of the value.</typeparam>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        /// <param name="dependency">The dependency.</param>
        /// <param name="absoluteexpiration">The absoluteexpiration.</param>
        /// <param name="slidingexpiration">The slidingexpiration.</param>
        /// <param name="updatecallback">The updatecallback.</param>
        /// <param name="condition">if set to <c>true</c> [condition].</param>
        /// <returns></returns>
        private static TValue SetValue<TValue>(string key, TValue value, CacheDependency dependency,
                                          DateTime absoluteexpiration, TimeSpan slidingexpiration,
                                          CacheItemUpdateCallback updatecallback, bool condition)
        {

            object obj = dic.Get(key);
            if (obj != null)
                return (TValue)obj;
            if (condition)
            {
                if (updatecallback != null)
                    dic.Insert(key, value, dependency, absoluteexpiration, slidingexpiration, updatecallback);
                else
                    dic.Insert(key, value, dependency, absoluteexpiration, slidingexpiration);
            }

            return value;
        }
        private static TValue SetValue<TValue>(string key, TValue value, bool condition)
        {
            if (condition && value != null)
                dic[key] = value;
            return value;
        }
    }

    #endregion
}